﻿using ExcellentProjectPlus.Dominio.Calificaciones.Entidades;
using ExcellentProjectPlus.Dominio.Calificaciones.Repositorios;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExcellentProjectPlus.Dominio.Calificaciones.Servicios.Parciales
{
    public class ServicioDeAdministracionDeParciales : IServicioDeAdministracionDeParciales
    {
        #region Atributos
        IUnidadDeTrabajoCalificaciones _unidadDeTrabajo;
        #endregion

        #region Constructores
        public ServicioDeAdministracionDeParciales(IUnidadDeTrabajoCalificaciones unidadDeTrabajo)
        {
            _unidadDeTrabajo = unidadDeTrabajo;
        }
        #endregion

        public IEnumerable<Parcial> ObtenerParciales()
        {
            return _unidadDeTrabajo.RepositorioParciales.Obtener();
        }

        public IEnumerable<Parcial> ObtenerParcialesPaginado(int pagina, int tamanio)
        {
            return _unidadDeTrabajo.RepositorioParciales.Obtener(orderBy: c => c.OrderBy(cal => cal.FechaInicio),
                page: pagina, pageSize: tamanio);
        }

        Parcial IServicioDeAdministracionDeParciales.ObtenerParcialPorId(int id)
        {
            return _unidadDeTrabajo.RepositorioParciales.ObtenerPorId(id);
        }

        public void AgregarParcial(Parcial parcial)
        {
            var periodo = _unidadDeTrabajo.RepositorioPeriodos.ObtenerPorId(parcial.IdPeriodo);
            //los parciales deberán ser creados de acuerdo alrango del periodo al que pertenecen

            #region Validacion Fechas en relacion al limite del periodo
            if (parcial.FechaInicio < periodo.FechaInicio || parcial.FechaInicio >= periodo.FechaFin)
                throw new ArgumentOutOfRangeException("FechaInicio", "La fecha de inicio debe estar dentro del rango del periodo al que pertenece el parcial: "
                    + periodo.FechaInicio + " - " + periodo.FechaFin);

            if (parcial.FechaFin > periodo.FechaFin || parcial.FechaFin <= periodo.FechaInicio)
                throw new ArgumentOutOfRangeException("FechaFin", "La fecha de fin debe estar dentro del rango del periodo al que pertenece el parcial: "
                    + periodo.FechaInicio + " - " + periodo.FechaFin);
            #endregion

            var listaDeParciales = _unidadDeTrabajo.RepositorioParciales
                .Obtener(p => p.IdPeriodo == parcial.IdPeriodo).ToList();

            if (listaDeParciales.Any(p => parcial.FechaInicio >= p.FechaInicio
                                            && parcial.FechaInicio <= p.FechaFin))
                throw new ArgumentOutOfRangeException("parcial", "La fecha de inicio del parcial tiene conflictos con otro parcial existente");

            if (listaDeParciales.Any(p => parcial.FechaFin > p.FechaInicio
                                            && parcial.FechaFin <= p.FechaFin))
                throw new ArgumentOutOfRangeException("parcial", "La fecha de fin del parcial tiene conflictos con otro parcial existente");

            _unidadDeTrabajo.RepositorioParciales.Agregar(parcial);
            _unidadDeTrabajo.Confirmar();
        }

        public void ModificarParcial(Parcial parcial)
        {

            var periodo = _unidadDeTrabajo.RepositorioPeriodos.ObtenerPorId(parcial.IdPeriodo);
            //los parciales deberán ser creados de acuerdo alrango del periodo al que pertenecen

            #region Validacion Fechas en relacion al limite del periodo
            if (parcial.FechaInicio < periodo.FechaInicio || parcial.FechaInicio >= periodo.FechaFin)
                throw new ArgumentOutOfRangeException("FechaInicio", "La fecha de inicio debe estar dentro del rango del periodo al que pertenece el parcial: "
                    + periodo.FechaInicio + " - " + periodo.FechaFin);

            if (parcial.FechaFin > periodo.FechaFin || parcial.FechaFin <= periodo.FechaInicio)
                throw new ArgumentOutOfRangeException("FechaFin", "La fecha de fin debe estar dentro del rango del periodo al que pertenece el parcial: "
                    + periodo.FechaInicio + " - " + periodo.FechaFin);
            #endregion

            var listaDeParciales = _unidadDeTrabajo.RepositorioParciales
                .Obtener(p => p.IdPeriodo == parcial.IdPeriodo).ToList();

            if (listaDeParciales.Any(p => parcial.FechaInicio >= p.FechaInicio
                                            && parcial.FechaInicio <= p.FechaFin))
                throw new ArgumentOutOfRangeException("parcial", "La fecha de inicio del parcial tiene conflictos con otro parcial existente");

            if (listaDeParciales.Any(p => parcial.FechaFin > p.FechaInicio
                                            && parcial.FechaFin <= p.FechaFin))
                throw new ArgumentOutOfRangeException("parcial", "La fecha de fin del parcial tiene conflictos con otro parcial existente");


            _unidadDeTrabajo.RepositorioParciales.Modificar(parcial);
            _unidadDeTrabajo.Confirmar();
        }

        public void EliminarParcial(Parcial parcial)
        {
            _unidadDeTrabajo.RepositorioParciales.Eliminar(parcial);
            _unidadDeTrabajo.Confirmar();
        }


        public IEnumerable<Parcial> ObtenerParcialesPorIdDePeriodo(int idDePeriodo)
        {
            return _unidadDeTrabajo.RepositorioParciales.Obtener(p => p.IdPeriodo == idDePeriodo);
        }
    }
}
